package org.mca.mcaweb.dao;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaQuery;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

public class DAO<T> implements Serializable {

	private static final long serialVersionUID = -5760759379415630652L;

	private final Class<T> classe;
 
	private EntityManager em;
	
	public DAO(Class<T> classe, EntityManager em) {
		this.em = em;
		this.classe = classe;
	}
	
	public EntityManager getEm(){
		return this.em;
	}

	public void save(T t) {
		em.persist(t);
	}

	public void remove(T t) {
		em.remove(em.merge(t));
	}

	public void update(T t) {
		em.merge(t);
	}

	public List<T> listAll() {
		CriteriaQuery<T> query = em.getCriteriaBuilder().createQuery(classe);
		
		query.select(query.from(classe));

		List<T> lista = em.createQuery(query).getResultList();

		return lista;
	}

	public T findById(Long id) {
		T instancia = null;
		if (id != null) {
			instancia = em.find(classe, id);
		}
		return instancia;
	}
	
	public T findByIdPK(T t) {
		T instancia = null;
		if (t != null) {
			instancia = em.find(classe, t);
		}																						
		return instancia;
	}

	/**
	 * 
	 * @author César Habby
	 *
	 * @param condicao1 | Tipos suportados: 'eq': para IGUAL (campo = valor), 'isNull': para NULLO (campo)
	 * @param campo1 | Nome do atributo a ser comparado. Sempre obrigatório.
	 * @param valor1 | Valor a ser comparado com o atributo do 'campo1'. Valor não é utilizado se escolher a condição for: 'isNull'
	 * @return Retorna uma lista generica de um determinado do tipo do objeto instanciado, de acordo com os parametros. 
	 */
	@SuppressWarnings("unchecked")
	public List<T> genericList(String condicao1, String campo1, Object valor1, String condicao2, String campo2, Object valor2) {
		
		Session session = (Session) em.getDelegate();
		
		try {
			
			Criteria criteria = session.createCriteria(classe);
			
			if (condicao1 != null) {
				// Igual | Exemplo: Select * from classe where campo = valor
				if (condicao1 == "eq") {
					criteria.add(Restrictions.eq(campo1, valor1));
				}
				// É Nullo | Exemplo: Select * from classe where campo is null
				if (condicao1 == "isNull") {
					criteria.add(Restrictions.isNull(campo1));
				}

				if (condicao1 == "ilike") {
					criteria.add(Restrictions.ilike(campo1, valor1.toString(), MatchMode.START));
				}
			}
			
			if (condicao2 != null) {
				if (condicao2 == "eq") {
					criteria.add(Restrictions.eq(campo2, valor2));
				}
				if (condicao2 == "isNull") {
					criteria.add(Restrictions.isNull(campo2));
				}
				if (condicao2 == "ilike") {
					criteria.add(Restrictions.ilike(campo2, valor2.toString(), MatchMode.START));
				}
			}
			return criteria.list();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	@SuppressWarnings("unchecked")
	public List<T> genericListJoin(String tabela, String aliasTabela, String campoJoin, Object valorJoin) {
		Session session = (Session) em.getDelegate();
		
		Criteria criteria = session.createCriteria(classe); 
 		criteria.createAlias(tabela,aliasTabela)
 		.add(Restrictions.eq(aliasTabela + "." + campoJoin, valorJoin));
		
 		return criteria.list();
	}

}
